package com.game.scene;

import java.io.IOException;
import java.util.ArrayList;

import org.andengine.engine.camera.Camera;
import org.andengine.engine.camera.hud.HUD;
import org.andengine.engine.handler.timer.ITimerCallback;
import org.andengine.engine.handler.timer.TimerHandler;
import org.andengine.entity.IEntity;
import org.andengine.entity.modifier.LoopEntityModifier;
import org.andengine.entity.modifier.ScaleModifier;
import org.andengine.entity.scene.IOnSceneTouchListener;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.SpriteBackground;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.text.Text;
import org.andengine.entity.text.TextOptions;
import org.andengine.extension.physics.box2d.FixedStepPhysicsWorld;
import org.andengine.extension.physics.box2d.PhysicsConnector;
import org.andengine.extension.physics.box2d.PhysicsFactory;
import org.andengine.extension.physics.box2d.PhysicsWorld;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.texture.region.ITiledTextureRegion;
import org.andengine.util.SAXUtils;
import org.andengine.util.adt.align.HorizontalAlign;
import org.andengine.util.level.EntityLoader;
import org.andengine.util.level.constants.LevelConstants;
import org.andengine.util.level.simple.SimpleLevelEntityLoaderData;
import org.andengine.util.level.simple.SimpleLevelLoader;
import org.xml.sax.Attributes;

import android.hardware.SensorManager;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.ContactImpulse;
import com.badlogic.gdx.physics.box2d.ContactListener;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.Manifold;
import com.game.base.BaseScene;
import com.game.extras.LevelCompleteWindow;
import com.game.extras.LevelCompleteWindow.StarsCount;
import com.game.manager.SceneManager;
import com.game.manager.SceneManager.SceneType;
import com.game.object.Bala;
import com.game.object.Enemy;
import com.game.object.OnDieScreenListener;
import com.game.object.Programmer;
import com.game.object.Proyectil;

/**
 * @author Erick Laynus
 * @version 1.0
 */
public class GameFightScene extends BaseScene implements IOnSceneTouchListener {
	private int score = 0;

	private Text scoreText;
	private PhysicsWorld physicsWorld;
	private LevelCompleteWindow levelCompleteWindow;

	private static final String TAG_ENTITY = "entity";
	private static final String TAG_ENTITY_ATTRIBUTE_X = "x";
	private static final String TAG_ENTITY_ATTRIBUTE_Y = "y";
	private static final String TAG_ENTITY_ATTRIBUTE_TYPE = "type";

	private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM1 = "platform1";
	private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM2 = "platform2";
	private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM3 = "platform3";
	private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_COIN = "coin";
	private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLAYER = "player";
	private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_LEVEL_COMPLETE = "levelComplete";

	private Text gameOverText;
	private boolean gameOverDisplayed = false;
	private boolean firstTouch = false;

	private Programmer programmer;
	private Sprite sprBtnLanzarCodigo, sprBtnLeft, sprBtnRight, sprBtnJump;
	private ArrayList<Proyectil> listaSpriteProyectil;
	private Enemy sprEnemigo;
	private static int CAMERA_WIDTH = 800;
	private static int CAMERA_HEIGHT = 480;
	private static FixtureDef FIXTURE_DEF = PhysicsFactory.createFixtureDef(0,
			0.01f, 0.5f);
	
	private static final String ENTITY_PLATAFORMA_PRINCIPAL = "platformMain";
	private static String ENTITY_PROGRAMADOR = "programador";
	private static String ENTITY_PROYECTIL = "proyectil";
	private static String ENTITY_ENEMIGO = "enemigo";
	private static String ENTITY_BALA = "bala";
	
	@Override
	public void createScene() {

		camera.setBounds(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
		// camera.setBoundsEnabled(true);
		createGameOverText();
		createPhysics();
		createBackground();
		createControllers();
		// loadLevel(1);
		//

		// levelCompleteWindow = new LevelCompleteWindow(vbom);

		// setOnSceneTouchListener(this);
	}

	@Override
	public void onBackKeyPressed() {
		SceneManager.getInstance().loadMenuScene(engine);
	}

	@Override
	public SceneType getSceneType() {
		return SceneType.SCENE_GAME_FIGHT;
	}

	@Override
	public void disposeScene() {
		camera.setHUD(null);
		camera.setChaseEntity(null); // TODO
		camera.setCenter(400, 240);

		// TODO code responsible for disposing scene
		// removing all game scene objects.
	}

	public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent) {
		if (pSceneTouchEvent.isActionDown()) {
			if (!firstTouch) {
				firstTouch = true;
			} else {
				programmer.jump();
			}
		}
		return false;
	}

	private void createGameOverText() {
		gameOverText = new Text(0, 0, resourcesManager.font, "Game Over Lulu!", vbom);
	}

	private void displayGameOverText() {
		camera.setChaseEntity(null);
		gameOverText.setPosition(camera.getCenterX(), camera.getCenterY());
		attachChild(gameOverText);
		gameOverDisplayed = true;
	}


	private void createBackground() {

		// setBackground(new Background(Color.WHITE ));
		/*
		 * attachChild(new Sprite(0, 0, resourcesManager.textureBackground,
		 * vbom) {
		 * 
		 * @Override protected void preDraw(GLState pGLState, Camera pCamera) {
		 * super.preDraw(pGLState, pCamera); pGLState.enableDither();
		 * pCamera.setChaseEntity(this); } });
		 */
		final int centerX = (int) ((CAMERA_WIDTH - resourcesManager.textureBackground
				.getWidth()) / 2);
		final int centerY = (int) ((CAMERA_HEIGHT - resourcesManager.textureBackground
				.getHeight()) / 2);
		SpriteBackground bg = new SpriteBackground(new Sprite(CAMERA_WIDTH / 2,
				CAMERA_HEIGHT / 2, resourcesManager.textureBackground, vbom));
		setBackground(bg);

		float xtubeMain = camera.getWidth() / 2;
		float xcuartaParte = xtubeMain / 2;
		float xtubeLeft = xtubeMain - xcuartaParte;
		float xtubeRight = xtubeMain + xcuartaParte;
		attachChild(new Sprite(xtubeLeft, 287, resourcesManager.textureTower,
				vbom));
		attachChild(new Sprite(xtubeMain, 287, resourcesManager.textureTower,
				vbom));
		attachChild(new Sprite(xtubeRight, 287, resourcesManager.textureTower,
				vbom));

		sprEnemigo = new Enemy(xtubeRight - 20, 287,
				resourcesManager.tldTxtEvilPlayer, vbom, camera, physicsWorld) {
	

			@Override
			public void move() {
				// TODO Auto-generated method stub

			}
		};
		
		sprEnemigo.registerUpdateHandler(new TimerHandler(2f, true, new ITimerCallback() {
			
			public void onTimePassed(TimerHandler pTimerHandler) {
				// TODO Auto-generated method stub
				Bala bala = crearBalaEnemiga(sprEnemigo.getX(),
						sprEnemigo.getY(),
						resourcesManager.tldTxtBala,
						GameFightScene.this.camera);
				bala.dispararSprite(programmer,10F,programmer.getBody().getPosition().y);
				GameFightScene.this.attachChild(bala);
				
			}
		}));
		sprEnemigo.setNameBody(ENTITY_ENEMIGO);

		programmer = new Programmer(xtubeLeft, 287,
				resourcesManager.tldTxtPlayer, vbom, camera, physicsWorld) {
			@Override
			public void move() {
		

			}
		};
		programmer.setOnMuerteListener(new OnDieScreenListener() {
			
			public void onDie(Sprite spr) {
				// TODO Auto-generated method stub
				if (!gameOverDisplayed) {
					displayGameOverText();
				}	
			}
		});
		//programmer.limitarMovimientoEjesGameObject((int) xtubeLeft,
			//	(int) xtubeRight, 0, 0);
		
		sprEnemigo.limitarMovimientoEjesGameObject((int) xtubeLeft,
				(int) xtubeRight, 0, 0);
		
		programmer.setNameBody(ENTITY_PROGRAMADOR);
		
		attachChild(programmer);
		attachChild(sprEnemigo);

		Sprite levelObject = new Sprite(xtubeMain, 160,
				resourcesManager.textureTowerHorizontal, vbom);
		PhysicsFactory.createBoxBody(physicsWorld, levelObject,
				BodyType.StaticBody, FIXTURE_DEF).setUserData("platformMain");
		attachChild(levelObject);
	}

	private void addToScore(int i) {
		score += i;
		scoreText.setText("Score: " + score);
	}

	private void createPhysics() {
		physicsWorld = new FixedStepPhysicsWorld(60, new Vector2(0, -17), false);
		physicsWorld.setContactListener(contactListener());
		registerUpdateHandler(physicsWorld);
	}

	private Proyectil crearProyectil(float xPos, float yPos,
			ITiledTextureRegion texture, Camera camera) {

		PhysicsWorld physicsWorldProyectil = new PhysicsWorld(new Vector2(xPos,
				SensorManager.GRAVITY_DEATH_STAR_I), false);
		//this.registerUpdateHandler(physicsWorldProyectil);

		Proyectil proyectil = new Proyectil(xPos, yPos, texture, vbom, camera,
				physicsWorld) {

			@Override
			public void move() {
				// TODO Auto-generated method stub
				if (this.collidesWith(sprEnemigo) == true) {
					if (listaSpriteProyectil.contains(this)) {

						listaSpriteProyectil.remove(this);
						addToScore(10);
						removeSpriteBody(this);
					}

				}

			}
		};
		proyectil.setRebotable(true);
		proyectil.setNameBody(ENTITY_PROYECTIL);
		return proyectil;

	}
	
	private Bala crearBalaEnemiga(float xPos, float yPos,
			ITiledTextureRegion texture, Camera camera) {

		Bala bala = new Bala(xPos, yPos, texture, vbom, camera,
				physicsWorld) {

			@Override
			public void move() {
				// TODO Auto-generated method stub
				if (this.collidesWith(programmer) == true) {

						addToScore(-10);
						removeSpriteBody(this);

				}
				
				if(listaSpriteProyectil != null)
				{
				for(Proyectil pro : listaSpriteProyectil)
				{
					if (this.collidesWith(pro) == true) {

						//addToScore(-10);
						removeSpriteBody(this);

					}
				}
				}
	

			}
		};
		
		
		
		bala.setRebotable(true);
		bala.setNameBody(ENTITY_BALA);
		bala.setOnMuerteListener(new OnDieScreenListener() {
			
			public void onDie(Sprite spr) {
				// TODO Auto-generated method stub
				removeSpriteBody(spr);	
			}
		});
		return bala;

	}

	
	private void removeSpriteBody(final Sprite s) {
		if (s == null) {
			return;
		}
		final PhysicsConnector physicsConnector =
				physicsWorld.getPhysicsConnectorManager().findPhysicsConnectorByShape(s);
	    if (physicsConnector != null)
        {
             physicsWorld.unregisterPhysicsConnector(physicsConnector);
             physicsWorld.destroyBody(physicsConnector.getBody()); 
             //body.setActive(false);
             //physicsWorld.destroyBody(body);
             s.detachSelf();
             s.dispose();
             //this.engine.getScene().detachChild(s);
        }

	}

	private void createControllers() {
		HUD yourHud = new HUD();
		sprBtnLeft = new Sprite(60, 60, resourcesManager.textureBtnLeft, vbom) {

			public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
					float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if (pSceneTouchEvent.isActionUp()) {
					programmer.pararBody();

				}
				if (pSceneTouchEvent.isActionDown()) {
					programmer.moverEjeX_Izquierda();
				}
				return true;

			}
		};
		sprBtnRight = new Sprite(140, 60, resourcesManager.textureBtnRight,
				vbom) {

			public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
					float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if (pSceneTouchEvent.isActionUp()) {
					programmer.pararBody();
				}
				if (pSceneTouchEvent.isActionDown()) {
					programmer.moverEjeX_Derecha();

				}
				return true;

			}
		};

		sprBtnJump = new Sprite(100, 140, resourcesManager.textureBtnJump, vbom) {

			public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
					float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if (pSceneTouchEvent.isActionUp()) {
					// move player left
					// programmer.jump();

				}
				if (pSceneTouchEvent.isActionDown()) {
					programmer.jump();
				}
				return true;

			}
		};

		sprBtnLanzarCodigo = new Sprite(camera.getWidth() - 50, 80,
				resourcesManager.textureBtnLanzarCodigo, vbom) {
			@Override
			public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
					float pTouchAreaLocalX, float pTouchAreaLocalY) {
				if (pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN) {

					Proyectil pro = crearProyectil(programmer.getX(),
							programmer.getY(),
							resourcesManager.tldTxtProyectil,
							GameFightScene.this.camera);
					pro.dispararEjeX_Derecha(programmer.getBody().getPosition().y);
					GameFightScene.this.attachChild(pro);
					if (listaSpriteProyectil == null) {
						listaSpriteProyectil = new ArrayList<Proyectil>();
					}
					listaSpriteProyectil.add(pro);

				}
				// TODO Auto-generated method stub
				return super.onAreaTouched(pSceneTouchEvent, pTouchAreaLocalX,
						pTouchAreaLocalY);
			}
		};

		scoreText = new Text(0, camera.getHeight() - 55, resourcesManager.font,
				"Score: 0123456789", new TextOptions(HorizontalAlign.LEFT),
				vbom);
		scoreText.setAnchorCenter(0, 0);
		scoreText.setText("Score: 0");

		yourHud.registerTouchArea(sprBtnLeft);
		yourHud.registerTouchArea(sprBtnRight);
		yourHud.registerTouchArea(sprBtnJump);
		yourHud.registerTouchArea(sprBtnLanzarCodigo);
		yourHud.attachChild(sprBtnLeft);
		yourHud.attachChild(sprBtnRight);
		yourHud.attachChild(sprBtnJump);
		yourHud.attachChild(scoreText);
		yourHud.attachChild(sprBtnLanzarCodigo);

		this.engine.getCamera().setHUD(yourHud);
	}

	// ---------------------------------------------
	// INTERNAL CLASSES
	// ---------------------------------------------

	private ContactListener contactListener() {
		ContactListener contactListener = new ContactListener() {
			public void beginContact(Contact contact) {
				final Fixture x1 = contact.getFixtureA();
				final Fixture x2 = contact.getFixtureB();

				if (x1.getBody().getUserData() != null
						&& x2.getBody().getUserData() != null) {
					if (x2.getBody().getUserData().equals(ENTITY_PROGRAMADOR)) {
						// programmer.increaseFootContacts();
						String str = "" + "";
						str = "";
					}
					
					if (x2.getBody().getUserData().equals(ENTITY_PROYECTIL)
							&& x1.getBody().getUserData().equals(ENTITY_ENEMIGO)) 
					{
				
						
					}

					if (x1.getBody().getUserData().equals(ENTITY_PROYECTIL)
							&& x2.getBody().getUserData().equals(ENTITY_ENEMIGO)) 
					{
						
				
			
		/*				engine.registerUpdateHandler(new TimerHandler(0.2f,
								new ITimerCallback() {
									public void onTimePassed(
											final TimerHandler pTimerHandler) {
										pTimerHandler.reset();
										engine.unregisterUpdateHandler(pTimerHandler);
										x1.getBody().setType(
												BodyType.DynamicBody);
									}
								}));*/
					}

					if (x1.getBody().getUserData().equals("platform3")
							&& x2.getBody().getUserData().equals("player")) {
						x1.getBody().setType(BodyType.DynamicBody);
					}
				}
			}

			public void endContact(Contact contact) {
				final Fixture x1 = contact.getFixtureA();
				final Fixture x2 = contact.getFixtureB();

				if (x1.getBody().getUserData() != null
						&& x2.getBody().getUserData() != null) {
					if (x2.getBody().getUserData().equals("player")) {
						// programmer.decreaseFootContacts();
					}
				}
			}

			public void preSolve(Contact contact, Manifold oldManifold) {

			}

			public void postSolve(Contact contact, ContactImpulse impulse) {

			}
		};
		return contactListener;
	}

	private void loadLevel(int levelID) {
		final SimpleLevelLoader levelLoader = new SimpleLevelLoader(vbom);

		final FixtureDef FIXTURE_DEF = PhysicsFactory.createFixtureDef(0,
				0.01f, 0.5f);

		levelLoader
				.registerEntityLoader(new EntityLoader<SimpleLevelEntityLoaderData>(
						LevelConstants.TAG_LEVEL) {
					public IEntity onLoadEntity(
							final String pEntityName,
							final IEntity pParent,
							final Attributes pAttributes,
							final SimpleLevelEntityLoaderData pSimpleLevelEntityLoaderData)
							throws IOException {
						final int width = SAXUtils.getIntAttributeOrThrow(
								pAttributes,
								LevelConstants.TAG_LEVEL_ATTRIBUTE_WIDTH);
						final int height = SAXUtils.getIntAttributeOrThrow(
								pAttributes,
								LevelConstants.TAG_LEVEL_ATTRIBUTE_HEIGHT);

						camera.setBounds(0, 0, width, height); // here we set
																// camera bounds
						camera.setBoundsEnabled(true);

						return GameFightScene.this;
					}
				});

		levelLoader
				.registerEntityLoader(new EntityLoader<SimpleLevelEntityLoaderData>(
						TAG_ENTITY) {
					public IEntity onLoadEntity(
							final String pEntityName,
							final IEntity pParent,
							final Attributes pAttributes,
							final SimpleLevelEntityLoaderData pSimpleLevelEntityLoaderData)
							throws IOException {
						final int x = SAXUtils.getIntAttributeOrThrow(
								pAttributes, TAG_ENTITY_ATTRIBUTE_X);
						final int y = SAXUtils.getIntAttributeOrThrow(
								pAttributes, TAG_ENTITY_ATTRIBUTE_Y);
						final String type = SAXUtils.getAttributeOrThrow(
								pAttributes, TAG_ENTITY_ATTRIBUTE_TYPE);

						final Sprite levelObject;

						if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM1)) {
							levelObject = new Sprite(x, y,
									resourcesManager.platform1_region, vbom);
							PhysicsFactory.createBoxBody(physicsWorld,
									levelObject, BodyType.StaticBody,
									FIXTURE_DEF).setUserData("platform1");
						} else if (type
								.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM2)) {
							levelObject = new Sprite(x, y,
									resourcesManager.platform2_region, vbom);
							final Body body = PhysicsFactory.createBoxBody(
									physicsWorld, levelObject,
									BodyType.StaticBody, FIXTURE_DEF);
							body.setUserData("platform2");
							physicsWorld
									.registerPhysicsConnector(new PhysicsConnector(
											levelObject, body, true, false));
						} else if (type
								.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLATFORM3)) {
							levelObject = new Sprite(x, y,
									resourcesManager.platform3_region, vbom);
							final Body body = PhysicsFactory.createBoxBody(
									physicsWorld, levelObject,
									BodyType.StaticBody, FIXTURE_DEF);
							body.setUserData("platform3");
							physicsWorld
									.registerPhysicsConnector(new PhysicsConnector(
											levelObject, body, true, false));
						} else if (type
								.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_COIN)) {
							levelObject = new Sprite(x, y,
									resourcesManager.coin_region, vbom) {
								@Override
								protected void onManagedUpdate(
										float pSecondsElapsed) {
									super.onManagedUpdate(pSecondsElapsed);

									if (programmer.collidesWith(this)) {
										addToScore(10);
										this.setVisible(false);
										this.setIgnoreUpdate(true);
									}
								}
							};
							levelObject
									.registerEntityModifier(new LoopEntityModifier(
											new ScaleModifier(1, 1, 1.3f)));
						} else if (type
								.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLAYER)) {
							programmer = new Programmer(x, y,
									resourcesManager.tldTxtPlayer, vbom,
									camera, physicsWorld) {

					

								@Override
								public void move() {
									// TODO Auto-generated method stub

								}
							};

							levelObject = programmer;
						} else if (type
								.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_LEVEL_COMPLETE)) {
							levelObject = new Sprite(x, y,
									resourcesManager.complete_stars_region,
									vbom) {
								@Override
								protected void onManagedUpdate(
										float pSecondsElapsed) {
									super.onManagedUpdate(pSecondsElapsed);

									if (programmer.collidesWith(this)) {
										levelCompleteWindow.display(
												StarsCount.TWO,
												GameFightScene.this, camera);
										this.setVisible(false);
										this.setIgnoreUpdate(true);
									}
								}
							};
							levelObject
									.registerEntityModifier(new LoopEntityModifier(
											new ScaleModifier(1, 1, 1.3f)));
						} else {
							throw new IllegalArgumentException();
						}

						levelObject.setCullingEnabled(true);

						return levelObject;
					}
				});

		levelLoader.loadLevelFromAsset(activity.getAssets(), "level/" + levelID
				+ ".lvl");
	}

}